package com.hwtx.form.domain.service;

import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.hwtx.form.annotation.Action;
import com.hwtx.form.annotation.Parameter;
import com.hwtx.form.domain.FormConstants;
import com.hwtx.form.domain.def.Select;
import com.hwtx.form.domain.def.meta.Api;
import com.hwtx.form.domain.ds.DataSourceContextHolder;
import com.hwtx.form.domain.handle.FormDataHandle;
import com.hwtx.form.domain.handle.datamodel.DataModel;
import com.hwtx.form.domain.handle.datamodel.DataModelDetail;
import com.hwtx.form.domain.handle.datamodel.DataModelRelate;
import com.hwtx.form.domain.repo.ApiRepo;
import com.hwtx.form.domain.repo.DataModelRepo;
import com.hwtx.form.domain.vo.DataModelDetailQuery;
import com.hwtx.form.persistence.DataSourceRepo;
import com.hwtx.form.persistence.entity.ApiDef;
import com.hwtx.form.persistence.entity.ApiDefField;
import com.hwtx.form.util.*;
import io.geekidea.boot.framework.exception.BusinessException;
import jakarta.annotation.Resource;
import lombok.Builder;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.hwtx.form.domain.FormConstants.DefaultColumn.*;
import static com.hwtx.form.domain.FormConstants.*;
import static com.hwtx.form.domain.FormConstants.OperatorType.IN;
import static com.hwtx.form.util.FormUtil.dataSourceInvoke;
import static io.geekidea.boot.generator.constant.GeneratorConstant.ID;

@Service
@Slf4j
public class CommonApiInvoker {
    @Resource
    DataModelRepo dataModelRepo;
    @Resource
    JdbcTemplate jdbcTemplate;
    @Resource
    ApiRepo apiRepo;
    @Resource
    private DataSourceRepo dataSourceRepo;

    public static List<Select.Option> getSelectResult(InvokeData invokeData) {
        AtomicBoolean labelEqValue = new AtomicBoolean(false);
        if (invokeData.getSelectItems().size() == 1) {
            labelEqValue.set(true);
        }
        return invokeData.getRet().stream().map(item -> {
            Select.Option option = new Select.Option();
            option.setValue(item.get(invokeData.getSelectItems().get(0)).toString());
            if (labelEqValue.get()) {
                option.setLabel(option.getValue());
            } else {
                option.setLabel(item.get(invokeData.getSelectItems().get(1)).toString());
            }
            return option;
        }).toList();
    }

    public static Map<String, Object> getMapResult(InvokeData invokeData) {
        return invokeData.getRet().stream().collect(Collectors.toMap(item -> item.get(invokeData.getSelectItems().getFirst()).toString(),
                item -> item.get(invokeData.getSelectItems().get(1))));
    }

    public static Api getApiUrlWithValues(ApiDef apiDef, String domain, String contextPath, List<String> paramValues) {
        StringBuilder paramString = new StringBuilder();
        String url = domain + contextPath + API_PREFIX_URL + apiDef.getCode() + "/" + apiDef.getRetType().getValue();
        if (StringUtils.isNotBlank(apiDef.getParams())) {
            List<Param> params = JacksonUtil.json2Array(apiDef.getParams(), new TypeReference<>() {
            });
            if (params != null) {
                String method = apiDef.getMethod();
                if (method == null) {
                    method = FormConstants.HTTP_GET;
                }
                Map<String, Object> data = new HashMap<>();
                for (int i = 0; i < params.size(); i++) {
                    Param param = params.get(i);
                    if (param.getConditions() != null && param.getConditions().stream()
                            .anyMatch(condition -> Objects.equals(condition.getCOperator(), OperatorType.ANY.getSymbol()))) {
                        continue;
                    }
                    String value = null;
                    if (CollectionUtils.isNotEmpty(paramValues) && StringUtils.isNotBlank(paramValues.get(i))) {
                        value = paramValues.get(i);
                    }
                    if (value != null) {
                        if (method.equalsIgnoreCase(FormConstants.HTTP_GET)) {
                            paramString.append(param.getName()).append("=").append(value).append("&");
                        } else if (method.equalsIgnoreCase(FormConstants.HTTP_POST)) {
                            data.put(param.getName(), value);
                        }
                    }
                }

                if (method.equalsIgnoreCase(FormConstants.HTTP_GET)) {
                    if (!paramString.isEmpty()) {
                        paramString.deleteCharAt(paramString.length() - 1);
                        url = url + "?" + paramString;
                    }
                    return Api.builder().url(url).method(method).build();
                } else if (method.equalsIgnoreCase(FormConstants.HTTP_POST)) {
                    return Api.builder().method(method).url(url).data(data).build();
                }
            }
        }
        return Api.builder().url(url).build();
    }

    public static List<String> getInputParamNames(ApiDef apiDef) {
        List<Param> params = getInputParams(apiDef);
        if (params != null) {
            return params.stream().map(Param::getName).toList();
        }
        return Lists.newArrayList();
    }

    public static List<Param> getInputParams(ApiDef apiDef) {
        if (apiDef.getParams() != null) {
            return JacksonUtil.json2Array(apiDef.getParams(), new TypeReference<>() {
            });
        }
        return null;
    }

    public static List<String> getOutputParamNames(ApiDef apiDef) {
        if (StringUtils.isBlank(apiDef.getExt())) {
            LambdaQueryWrapper<ApiDefField> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ApiDefField::getApiCode, apiDef.getCode());
            return SpringUtil.getBean(ApiRepo.class).getApiDefFields(ApiRepo.ApiDefFieldQuery.builder().apiCode(apiDef.getCode()).build()).stream().map(ApiDefField::getName).toList();
        }
        Action action = FormUtil.getMethodAction(apiDef);
        if (action == null) {
            throw new BusinessException("未找到API方法");
        }
        return Arrays.stream(action.outputs()).map(Parameter::name).toList();
    }

    public InvokeData invokeApi(ApiDef apiDef, Map<String, String[]> parameters) {
        String[] test = parameters.get("test");
        boolean isTest = false;
        if (test != null) {
            isTest = Boolean.parseBoolean(test[0]);
        }
        if (!isTest && (apiDef == null || Objects.equals(FormConstants.API_TEST, apiDef.getStatus()))) {
            throw new BusinessException("请求的接口不存在或处于测试状态");
        }
        List<Param> apiParams = null;
        if (StringUtils.isNotBlank(apiDef.getParams())) {
            apiParams = JacksonUtil.json2Array(apiDef.getParams(), new TypeReference<>() {
            });
        }
        Map<String, Object> invokeParams = Maps.newHashMap();
        parameters.forEach((key, value) -> invokeParams.put(key, value[0]));
        if (StringUtils.isNotEmpty(apiDef.getModelName())) {
            return invokeModel(apiDef, invokeParams, Maps.newHashMap(), apiParams);
        }
        return invokeExt(apiDef, invokeParams, apiParams);
    }

    public InvokeData invokeApiNoCareTest(ApiDef apiDef, Map<String, Object> parameters, Map<String, String> extraParameters) {
        List<Param> apiParams = null;
        if (StringUtils.isNotBlank(apiDef.getParams())) {
            apiParams = JacksonUtil.json2Array(apiDef.getParams(), new TypeReference<>() {
            });
        }
        if (apiDef.getModelName() != null) {
            return invokeModel(apiDef, parameters, extraParameters, apiParams);
        }
        return invokeExt(apiDef, parameters, apiParams);
    }

    public InvokeData invokeApiNoCareTest(ApiDef apiDef, Map<String, Object> parameters) {
        return invokeApiNoCareTest(apiDef, parameters, null);
    }

    public InvokeData invokeApi(String code, Map<String, String[]> parameters) {
        try {
            DataSourceContextHolder.setDefaultDsKey();
            ApiDef apiDef = apiRepo.getOne(new LambdaQueryWrapper<ApiDef>().eq(ApiDef::getCode, code));
            return invokeApi(apiDef, parameters);
        } finally {
            DataSourceContextHolder.clearDataSourceKey();
        }
    }

    private InvokeData invokeExt(ApiDef apiDef, Map<String, Object> invokeParams, List<Param> apiParams) {
        String ext = apiDef.getExt();
        if (StringUtils.isBlank(ext)) {
            throw new RuntimeException("当前接口未配置扩展接口");
        }
        String[] handleInfo = ext.split(",");
        try {
            Map<String, Object> content = Maps.newHashMap();
            apiParams.forEach(param -> content.put(param.getName(), invokeParams.get(param.getName())));
            FormDataHandle formDataHandle = SpringUtil.getBean(handleInfo[0], FormDataHandle.class);
            return InvokeData.builder().retData(formDataHandle.getClass().getMethod(handleInfo[1], Map.class).invoke(formDataHandle, content)).extInvoke(true).build();
        } catch (Exception e) {
            log.error("调用扩展接口失败", e);
            if (e instanceof InvocationTargetException) {
                throw new BusinessException(((InvocationTargetException) e).getTargetException());
            }
            throw new BusinessException(e);
        }
    }

    private InvokeData invokeModel(ApiDef apiDef, Map<String, Object> invokeParams, Map<String, String> extraParameters, List<Param> apiParams) {
        Map<String, Map<String, String>> searchItems = Maps.newHashMap();
        List<String> fields = Lists.newArrayList();
        Object dsRet = dataSourceInvoke(DataSourceContextHolder.getDefaultDs(),
                () -> {
                    if (!Objects.equals(apiDef.getWr(), WR_READ)) {
                        return -1;
                    }
                    List<ApiDefField> selectFields = apiRepo.getApiDefFields(ApiRepo.ApiDefFieldQuery.builder().apiCode(apiDef.getCode()).build());
                    if (CollectionUtils.isEmpty(selectFields) && StringUtils.isNotEmpty(apiDef.getModelName())) {
                        throw new RuntimeException("当前接口未配置查询字段");
                    }
                    List<DataModelDetail> dataModelDetails = dataModelRepo.getDetails(DataModelDetailQuery.builder().ids(selectFields.stream().map(ApiDefField::getModelDetailId).collect(Collectors.toList())).build());
                    Map<Long, DataModelDetail> detailIdMapIt = dataModelDetails.stream().collect(Collectors.toMap(DataModelDetail::getId, Function.identity()));
                    DataModel dataModel = dataModelRepo.getDataModel(apiDef.getModelName());
                    if (dataModel == null) {
                        log.error("数据模型不存在,modelName={}", apiDef.getModelName());
                        return null;
                    }
                    if (DataModel.isAggTableModel(dataModel.getTableType()) && !Objects.equals(apiDef.getWr(), WR_READ)) {
                        throw new BusinessException("聚合模型不支持写操作");
                    }
                    if (DataModel.isSqlModel(dataModel.getModelType()) && !dataModel.getSqlContent().startsWith("select")) {
                        throw new BusinessException("sql模型只支持查询");
                    }
                    selectFields.forEach(apiField -> {
                        DataModelDetail dataModelDetail = detailIdMapIt.get(apiField.getModelDetailId());
                        if (dataModelDetail != null) {
                            searchItems.compute(apiField.getTableName(), (table, fieldAndAlias) -> {
                                if (fieldAndAlias == null) {
                                    fieldAndAlias = Maps.newHashMap();
                                }
                                fieldAndAlias.put(dataModelDetail.getName(), apiField.getName());
                                return fieldAndAlias;
                            });
                        }
                        fields.add(apiField.getName());
                    });
                    if (extraParameters != null) {
                        extraParameters.forEach((key, value) -> {
                            if (!fields.contains(key)) {
                                searchItems.compute(dataModel.getMaster(), (table, fieldAndAlias) -> {
                                    if (fieldAndAlias == null) {
                                        fieldAndAlias = Maps.newHashMap();
                                    }
                                    fieldAndAlias.put(key, value);
                                    return fieldAndAlias;
                                });
                                fields.add(key);
                            } else {
                                Map<String, String> fieldAndAlias = searchItems.get(dataModel.getMaster());
                                if (fieldAndAlias != null && !Objects.equals(value, fieldAndAlias.get(key))) {
                                    fieldAndAlias.put(key, value);
                                }
                                searchItems.put(dataModel.getMaster(), fieldAndAlias);
                            }
                        });
                    }
                    return -1;
                });
        if (dsRet == null) {
            return null;
        }
        InvokeParamConfig invokeParamConfig = InvokeParamConfig.builder().dataModel(apiDef.getModelName())
                .params(apiParams).output(searchItems).build();
        if (Objects.equals(apiDef.getWr(), WR_READ)) {
            List<Map<String, Object>> ret = invokeRead(invokeParamConfig, invokeParams);
            return InvokeData.builder().ret(ret).selectItems(fields).build();
        }
        if (extraParameters.containsKey(WR_WRITE_DEL)) {
            return InvokeData.builder().ret(invokeDel(invokeParamConfig, invokeParams)).selectItems(fields).build();
        }
        return InvokeData.builder().ret(invokeWrite(invokeParamConfig, invokeParams)).selectItems(fields).build();
    }

    private List<Map<String, Object>> invokeDel(InvokeParamConfig invokeParamConfig, Map<String, Object> parameters) {
        String ids = parameters.get(WR_WRITE_DEL_IDS).toString();
        if (StringUtils.isBlank(ids)) {
            throw new RuntimeException("未传入删除ID");
        }
        DataModel dataModel = getDataModel(invokeParamConfig.getDataModel());
        SQL sql = new SQL();
        sql.DELETE_FROM(dataModel.getMaster());
        sql.WHERE(ID + " IN (" + String.join(",", ids) + ")");
        boolean ret = dataSourceInvoke(dataModel.getDs(), () -> jdbcTemplate.update(sql.toString())) > 0;
        return Lists.newArrayList(Map.of("ret", ret));
    }

    private List<Map<String, Object>> invokeWrite(InvokeParamConfig invokeParamConfig, Map<String, Object> parameters) {
        List<Param> params = invokeParamConfig.getParams();
        if (CollectionUtils.isEmpty(params)) {
            params = Lists.newArrayList();
        }
        DataModel dataModel = getDataModel(invokeParamConfig.getDataModel());
        SQL sql = new SQL();
        List<String> columns = Lists.newArrayList();
        List<Object> values = Lists.newArrayList();
        List<String> placeholders = Lists.newArrayList();

        params.stream().filter(input -> !Objects.equals(ID, input.getField())).forEach(input -> {
            if (BooleanUtils.toBoolean(input.getRequired())) {
                if (parameters.get(input.getName()) == null) {
                    throw new BusinessException("参数" + input.getName() + "不能为空");
                }
            }
            columns.add(input.getField());
            values.add(parameters.get(input.getName()));
            placeholders.add("?");
        });
        Object id = parameters.get(ID);
        boolean ret;
        if (id == null) {
            sql.INSERT_INTO(dataModel.getMaster());
            sql.INTO_COLUMNS(columns.toArray(new String[0])).INTO_COLUMNS(getDefaultColumns().toArray(new String[0]));
            sql.INTO_VALUES(placeholders.toArray(new String[0])).INTO_VALUES("?", "?", "?", "?");
            ret = dataSourceInvoke(dataModel.getDs(), () -> jdbcTemplate.update(sql.toString(), ps -> {
                AtomicInteger index = new AtomicInteger(1);
                values.forEach(v -> {
                    try {
                        ps.setObject(index.getAndIncrement(), v);
                    } catch (SQLException e) {
                        throw new RuntimeException(e);
                    }
                });
                getCreateDefaultColumns().forEach((k, v) -> {
                    try {
                        ps.setObject(index.getAndIncrement(), v);
                    } catch (SQLException e) {
                        throw new RuntimeException(e);
                    }
                });
            })) > 0;
        } else {
            sql.UPDATE(dataModel.getMaster());
            columns.forEach(column -> sql.SET(column + " = ?"));
            getModifyDefaultColumns().forEach((column, v) -> {
                sql.SET(column + " = ?");
                values.add(v);
            });
            sql.WHERE(Param.buildExpr(ID, "=", id, false));
            values.add(parameters.get(ID));
            ret = dataSourceInvoke(dataModel.getDs(), () -> jdbcTemplate.update(sql.toString(), values.toArray())) > 0;
        }
        return Lists.newArrayList(Map.of("ret", ret));
    }

    private List<Map<String, Object>> invokeRead(InvokeParamConfig invokeParamConfig, Map<String, Object> parameters) {
        List<Param> params = invokeParamConfig.getParams();
        if (CollectionUtils.isEmpty(params)) {
            params = Lists.newArrayList();
        }
        if (MapUtils.isEmpty(invokeParamConfig.getOutput())) {
            throw new BusinessException("输出配置为空");
        }
        Map<Param, List<Param.Condition>> fieldRules = Maps.newHashMap();
        Map<String, Object> fieldValues = Maps.newHashMap();
        params.forEach(input -> {
            Object inputValue = parameters.get(input.getName());
            if (BooleanUtils.toBoolean(input.getRequired()) && CollectionUtils.isEmpty(input.getConditions())) {
                if (inputValue == null) {
                    throw new BusinessException("参数" + input.getName() + "不能为空");
                }
            }
            fieldRules.put(input, input.getConditions());
            if (inputValue != null) {
                fieldValues.put(input.getField(), inputValue);
            }
        });
        DataModel dataModel = getDataModel(invokeParamConfig.getDataModel());
        if (DataModel.isAggTableModel(dataModel.getTableType())) {
            return getAggValues(invokeParamConfig, dataModel, fieldRules, fieldValues);
        } else if (DataModel.isSqlModel(dataModel.getModelType())) {
            return getSqlValues(invokeParamConfig, dataModel, fieldRules, fieldValues);
        }
        return getValues(dataModel, invokeParamConfig, fieldRules, fieldValues);
    }

    private List<Map<String, Object>> getSqlValues(InvokeParamConfig invokeParamConfig, DataModel dataModel, Map<Param, List<Param.Condition>> rules, Map<String, Object> fieldValues) {
        List<Object> param = Lists.newArrayList();
        String sql = dataModel.getSqlContent();
        if (MapUtils.isNotEmpty(rules)) {
            for (Param paramConfig : rules.keySet()) {
                Object value = fieldValues.get(paramConfig.getField());
                if (Types.isCollection(paramConfig.getType())) {
                    Collection<?> values = Lists.newArrayList();
                    if (value instanceof Collection<?>) {
                        values = (Collection<?>) value;
                    } else if (value instanceof String) {
                        values = Arrays.asList(value.toString().split(","));
                    }
                    param.addAll(values);
                } else {
                    if (BooleanUtils.toBoolean(paramConfig.getRequired())) {
                        if (value == null) {
                            throw new BusinessException("参数" + paramConfig.getName() + "不能为空");
                        }
                        param.add(value);
                    } else {
                        if (value == null) {
                            continue;
                        }
                        if (value instanceof String) {
                            if (StringUtils.isNotEmpty(value.toString())) {
                                param.add(value);
                            }
                        } else {
                            param.add(value);
                        }
                    }
                }
                if (sql.contains("@" + paramConfig.getName())) {
                    if (value instanceof Collection<?>) {
                        sql = sql.replace("@" + paramConfig.getName(), ((Collection<?>) value).stream().map(v -> "?").collect(Collectors.joining(",")));
                    } else {
                        sql = sql.replace("@" + paramConfig.getName(), "?");
                    }
                }
            }
        }
        String finalSql = sql;
        List<Map<String, Object>> ret = dataSourceInvoke(dataModel.getDs(), () -> jdbcTemplate.queryForList(finalSql, param.toArray()));
        List<String> output = Lists.newArrayList();
        invokeParamConfig.getOutput().forEach((k, v) -> v.forEach((field, alias) -> {
            output.add(StringUtils.isNotBlank(alias) ? alias : field);
        }));
        return ret.stream().map(item -> {
            Map<String, Object> map = Maps.newHashMap();
            item.forEach((k, v) -> {
                if (output.contains(k)) {
                    map.put(k, v);
                }
            });
            return map;
        }).collect(Collectors.toList());
    }

    private List<Map<String, Object>> getAggValues(InvokeParamConfig invokeParamConfig, DataModel dataModel, Map<Param, List<Param.Condition>> rules, Map<String, Object> fieldValues) {
        List<DataModelRelate> relates = dataModelRepo.getRelates(dataModel.getModelName());
        if (CollectionUtils.isEmpty(relates)) {
            return getValues(dataModel, invokeParamConfig, rules, fieldValues);
        }
        SQL sql = new SQL();
        List<String> hasHandleTables = Lists.newArrayList();
        AtomicInteger index = new AtomicInteger(1);
        Map<String, String> tableAndAlias = Maps.newHashMap();
        relates.forEach(relate -> {
            if (!hasHandleTables.contains(relate.getFirstName())) {
                tableAndAlias.put(relate.getFirstName(), "t" + index.getAndIncrement());
                hasHandleTables.add(relate.getFirstName());
            }

            if (!hasHandleTables.contains(relate.getSecondName())) {
                tableAndAlias.put(relate.getSecondName(), "t" + index.getAndIncrement());
                hasHandleTables.add(relate.getSecondName());
            }
            dataSourceRepo.buildJoinInfo(sql, tableAndAlias, JacksonUtil.json2Array(relate.getJoinFields()), relate, index, FormConstants.JoinType.of(relate.getJoinType()));
        });
        buildSelectItem(invokeParamConfig, sql, tableAndAlias);
        return whereAndRun(rules, fieldValues, sql, dataModel.getDs());
    }

    private List<Map<String, Object>> getValues(DataModel dataModel, InvokeParamConfig invokeParamConfig, Map<Param, List<Param.Condition>> rules, Map<String, Object> fieldValues) {
        SQL sql = new SQL();
        buildSelectItem(invokeParamConfig, sql, null);
        sql.FROM(dataModel.getMaster());
        sql.WHERE("1=1");
        return whereAndRun(rules, fieldValues, sql, dataModel.getDs());
    }

    private void buildSelectItem(InvokeParamConfig invokeParamConfig, SQL sql, Map<String, String> tableAndAlias) {
        invokeParamConfig.getOutput().forEach((table, fieldAndAlias) -> fieldAndAlias.forEach((field, alias) -> {
            String tableAlias = null;
            if (tableAndAlias != null) {
                tableAlias = tableAndAlias.get(table);
            }
            if (StringUtils.isNotBlank(alias)) {
                field = tableAlias != null ? tableAlias + "." + field : field;
                sql.SELECT(field + " as " + alias);
            } else {
                sql.SELECT(field);
            }
        }));
    }

    private List<Map<String, Object>> whereAndRun(Map<Param, List<Param.Condition>> rules, Map<String, Object> fieldValues, SQL sql, String ds) {
        List<Object> param = Lists.newArrayList();
        if (MapUtils.isNotEmpty(rules)) {
            rules.forEach((paramConfig, conditions) -> {
                Object value = fieldValues.get(paramConfig.getField());
                if (CollectionUtils.isNotEmpty(conditions)) {
                    conditions.forEach(condition -> {
                        Param.ExprRet exprRet = Param.getExpression(paramConfig, condition, value);
                        if (exprRet != null) {
                            sql.WHERE(exprRet.getExpr());
                            if (exprRet.isParam()) {
                                param.add(value);
                            }
                        }
                    });
                } else {
                    String operator = paramConfig.getOperator();
                    Object paramValue = value;
                    if (Types.isCollection(paramConfig.getType())) {
                        Collection<?> values = Lists.newArrayList();
                        if (value instanceof Collection<?>) {
                            values = (Collection<?>) value;
                        } else if (value instanceof String) {
                            values = Arrays.asList(value.toString().split(","));
                        }
                        paramValue = values;
                        param.addAll(values);
                        operator = IN.getSymbol();
                    } else {
                        if (BooleanUtils.toBoolean(paramConfig.getRequired())) {
                            if (value == null) {
                                throw new BusinessException("参数" + paramConfig.getName() + "不能为空");
                            }
                            param.add(value);
                        } else {
                            if (value == null) {
                                return;
                            }
                            if (value instanceof String) {
                                if (StringUtils.isNotEmpty(value.toString())) {
                                    param.add(value);
                                } else {
                                    return;
                                }
                            } else {
                                param.add(value);
                            }
                        }
                    }
                    sql.WHERE(Param.buildExpr(paramConfig.getField(), operator, paramValue, false));
                }
            });
        }
        return dataSourceInvoke(ds, () -> jdbcTemplate.queryForList(sql.toString(), param.toArray()));
    }

    private DataModel getDataModel(String modelName) {
        DataModel dataModel = dataSourceInvoke(DataSourceContextHolder.getDefaultDs(), () -> dataModelRepo.getDataModel(modelName));
        if (dataModel == null) {
            throw new BusinessException("数据模型不存在,modelName = " + modelName);
        }
        return dataModel;
    }

    @Builder
    @Getter
    public static class InvokeData {
        List<Map<String, Object>> ret;
        List<String> selectItems;
        Object retData;
        boolean extInvoke;
    }

    @Getter
    @Builder
    public static class InvokeParamConfig {
        /**
         * 输入字段
         */
        List<Param> params;
        /**
         * 输出字段，模型字段
         */
        Map<String, Map<String, String>> output;
        /**
         * 模型名称
         */
        private String dataModel;
    }
}
